#include "networktask.h"
#include "networkscan.h"
#include "datapostback.h"
#include "mylogger.h"
#include "playvoice.h"
#include "DbSetting.h"
#include <QDateTime>
#include "enetwork.h"
#include "machineutil.h"
#include "lightcontrol.h"
#include "update/simpleupdate.h"
#include "update/stateupdate.h"
#include "update/updateutil.h"
#include "version.h"
#include "poicheck.h"
#include "model/modelmsg.h"
#include "dbalertlog.h"
#include "dbsystemlog.h"

using namespace ns_yht;
NetworkTask::NetworkTask(const QString &softwareCode)
{
    m_softwareCode = softwareCode;

    init();
    m_networkScan = new NetworkScan();
    connect(this, SIGNAL(signalToStartScan()), m_networkScan, SLOT(run()));
    connect(this, SIGNAL(signalToStopScan()), m_networkScan, SLOT(stop()));
    connect(m_networkScan, &NetworkScan::statusChanged, this, &NetworkTask::onNetworkStatusChanged);
    connect(m_networkScan, &NetworkScan::statusRefreshed, DATAPOSTBACK, &DataPostback::onNetworkStatusChanged);

    m_logPostback = new LogPostback();
    connect(this, &NetworkTask::signalToPostlog_alert, m_logPostback, &LogPostback::onPostlog_alert);
    connect(this, &NetworkTask::signalToPostlog_system, m_logPostback, &LogPostback::onPostlog_system);
    connect(this, &NetworkTask::signalToPostHeartbeat, m_logPostback, &LogPostback::onPostHeartbeat);

    m_networkScan->moveToThread(&m_networkScanThread);
    m_logPostback->moveToThread(&m_networkScanThread);
    m_networkScanThread.start();
}

NetworkTask::~NetworkTask()
{
    m_networkScanThread.quit();
    m_networkScanThread.wait();
    delete m_networkScan;
}

void NetworkTask::init()
{
    DbSetting dbSetting;
    qint64 lastStartTime = dbSetting.getSetting(SETTING_LASTSTARTTIME).toLongLong();
    m_rebootTimes = dbSetting.getSetting(SETTING_REBOOTTIMES).toInt();

    qint64 ctime = QDateTime::currentSecsSinceEpoch();
    dbSetting.saveSetting(SETTING_LASTSTARTTIME, QString::number(ctime));

    m_justRebooted = (qAbs(ctime - lastStartTime < 60));
    if (m_justRebooted)
    {
        dbSetting.saveSetting(SETTING_REBOOTTIMES, QString::number(m_rebootTimes + 1));
        GLOG->info(QString("boot times: %1").arg(m_rebootTimes + 1).toStdString());
    }
    else
    {
        dbSetting.saveSetting(SETTING_REBOOTTIMES, "1");
        GLOG->info("boot times: 1");
    }
}

void NetworkTask::startScan()
{
    emit signalToStartScan();
}

void NetworkTask::stopScan()
{
    emit signalToStopScan();
}

void NetworkTask::onNetworkStatusChanged(bool status)
{
    static bool isFirst = true;
    ENetwork::networkStatus = status;
    if (!status)
    {
        PLAYVOICE->play(PlayVoice::VoiceType::NetworkDisconnected);
        if (isFirst && !MyLogger::developDebug)
        {
            if ((m_justRebooted && m_rebootTimes < 3) || !m_justRebooted)
            {
                reboot();
            }
        }
    }
    else
    {
        PLAYVOICE->play(PlayVoice::VoiceType::NetworkConnected);

        if (TOKEN.isEmpty())
            tokenScan();
        else
            postPrelog();
    }
    isFirst = false;
}

void NetworkTask::reboot()
{
#ifdef Q_OS_LINUX
    QProcess process;
    process.startDetached("reboot", QStringList() << "-f");
    qApp->quit();
#endif
}

void NetworkTask::tokenScan()
{
    if (GLOG)
        GLOG->debug("start tokenScan......");
    QString url = QString("http://restapi.ehanghai.cn/xxyc-api/login/%1/%2").arg(MachineUtil::machineCode(), m_softwareCode);
    QNetworkReply *reply = ENetwork::Get(url, {}, {}, false);
    if (reply != nullptr)
    {
        connect(reply, &QNetworkReply::finished, this, [=]
                { onLoginTokenFinished(reply); });
        // 添加错误处理
        connect(reply, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::errorOccurred),
                this, [this, reply](QNetworkReply::NetworkError code)
                {
                    if (GLOG)
                        GLOG->error("Network error in tokenScan: {}", code);
                    reply->deleteLater(); });
    }
    else
    {
        if (GLOG)
            GLOG->error("Failed to create network request in tokenScan");
    }
}

void NetworkTask::onLoginTokenFinished(QNetworkReply *reply)
{
    if (GLOG)
        GLOG->debug("end tokenScan......");
    if (ENetwork::checkReplyError(reply))
    {
        reply->deleteLater();
        // emit tokenError(2);
        return;
    }
    QJsonParseError jsonError;
    const QJsonDocument &jsonDocument = QJsonDocument::fromJson(reply->readAll(), &jsonError);
    reply->deleteLater();
    if (jsonError.error != QJsonParseError::NoError)
    {
        if (GLOG)
            GLOG->error("JSON parse error: {}", jsonError.errorString().toStdString());
        emit tokenError(2);
        return;
    }
    if (!jsonDocument.isNull())
    {
        const QJsonObject &rootObj = jsonDocument.object();

        if (rootObj.value("success").toBool())
        {
            TOKEN = rootObj.value("data").toString();
            if (GLOG)
                GLOG->debug("token: {}", TOKEN.toStdString());
            onTokenReceived();
        }
        else
        {
            // emit tokenError(1, rootObj.value("errorMsg").toString());
        }

#if 0
        if (rootObj.value("errorcode").toInt() == 0 && rootObj.contains("result"))
        {
            const QJsonObject &result = rootObj.value("result").toObject();
            if (result.contains("token"))
            {
                TOKEN = result.value(QStringLiteral("token")).toString();
                if (GLOG)
                    GLOG->debug("token: {}", TOKEN.toStdString());
                    // emit tokenReceived();
                // 原来是两小时后更新token，现在token的策略是3天没使用才过期，所以不需要定期获取token
            }
        }
        // else if (needEmit)
        // {
        //     emit tokenError(rootObj.value(QStringLiteral("errorcode")).toInt(), rootObj.value(QStringLiteral("reason")).toString());
        // }
#endif
    }
    // else
    // emit tokenError(2);
}

void NetworkTask::onTokenReceived()
{
#if 1 // yu
    static bool isFirst = true;
    if (isFirst)
    { // 开机时检查一次，如果距离上次更新超过一天，则需要更新风险区域
        // PLAYVOICE->play(PlayVoice::VoiceType::TokenReceived);
        ensureUpdateUtil();

        UPDATEUTIL->startScan();
        postPrelog();
// 电子狗改为手动下载风险区域数据
#if 1
        QSettings setting(QCoreApplication::applicationDirPath() + "/setting.ini", QSettings::IniFormat);
        qint64 lastUpdateTime = setting.value("RiskAreaUpdateTime", 1747843200).toLongLong(); // 2025-05-22 0:0:0
        qint64 now = QDateTime::currentSecsSinceEpoch();
        if (now - lastUpdateTime > 86400) // 1天
        {
            LIGHTTASK->startShrink(LightColor::Green);
            SIMPLEUPDATE->startRiskArea();
        }
        else
        {
            UPDATEUTIL->startScan();
        }
#endif

        isFirst = false;
    }
    else
        STATEUPDATE->startHeartBeat();
#endif
#if 0 // zld
                         if (m_type == 1)
                         {
                             SIMPLEUPDATE->startRiskArea();
                             m_type = 0;
                         }
                         else if (m_type == 2)
                         {
                             STATEUPDATE->startHeartBeat();
                             m_type = 0;
                         }
#endif
}

void NetworkTask::ensureUpdateUtil()
{
    if (!UPDATEUTIL)
    {
        QVector<QPair<QString, QString>> softwareVersions;
        QPair<QString, QString> pair;
        pair.first = SOFTWARECODE;
        pair.second = PROJECT_VERSION;
        softwareVersions.append(pair);
        new UpdateUtil(softwareVersions, QCoreApplication::applicationDirPath());
        connect(UPDATEUTIL, &UpdateUtil::scanFinished, this, &NetworkTask::onUpdateScanFinished);
        connect(UPDATEUTIL, &UpdateUtil::downloadFinished, this, &NetworkTask::onDownloadFinished);
        connect(UPDATEUTIL, &UpdateUtil::postlogFinished, this, &NetworkTask::onpostlogFinished);
        connect(UPDATEUTIL, &UpdateUtil::updateFailed, this, &NetworkTask::onUpdateFailed);
        connect(SIMPLEUPDATE, &SimpleUpdate::updateFinished, this, &NetworkTask::onBaseDataUpdateFinished);
    }
}

void NetworkTask::onBaseDataUpdateFinished(bool result)
{
    LIGHTTASK->stopShrink(LightColor::Green);
    LIGHTTASK->turnOn(LightColor::Green, true);
    if (result)
    {
        QSettings setting(QCoreApplication::applicationDirPath() + "/setting.ini", QSettings::IniFormat);
        setting.setValue("RiskAreaUpdateTime", QDateTime::currentSecsSinceEpoch());
        POICHECK->loadFeatures_yhtc();
        if (GLOG)
            GLOG->info("base data update finished");
        PLAYVOICE->play(PlayVoice::VoiceType::RiskAreaUpdateSucceed);
    }
    else
    {
        if (GLOG)
            GLOG->info("base data update failed");
        PLAYVOICE->play(PlayVoice::VoiceType::RiskAreaUpdateFailed);
    }
    UPDATEUTIL->startScan();
}

void NetworkTask::onUpdateScanFinished()
{
    if (UPDATEUTIL->getAppScan()->getModel()->state == VersionScanResult::Error) // 重新检查
    {
        UPDATEUTIL->startScan();
    }
    else if (UPDATEUTIL->needUpdate())
    {
        PLAYVOICE->play(PlayVoice::VoiceType::StartSystemUpdate);
        UPDATEUTIL->updateAll();
    }
}

void NetworkTask::onDownloadFinished()
{
    // m_update = true;
}

void NetworkTask::onUpdateFailed()
{
    PLAYVOICE->play(PlayVoice::VoiceType::SystemUpdateFailed);
}

void NetworkTask::onpostlogFinished()
{
    PLAYVOICE->play(PlayVoice::VoiceType::SystemUpdateSucceed);
    QTimer::singleShot(5000, [=]
                       { reboot(); });
}

void NetworkTask::postPrelog()
{
    DbSystemLog dbSystemLog;
    QVector<QSharedPointer<ModelSystemLog>> modelList;
    bool ret = dbSystemLog.getUnPostedList(modelList);
    if (ret && modelList.size() > 0)
    {
        foreach (const auto &model, modelList)
        {
            if (model->stype == 0)
                emit signalToPostlog_system(1, model->stime);
        }
    }
    dbSystemLog.updatePosted();

    DbAlertLog dbAlertLog;
    QVector<QSharedPointer<ModelMsg>> modelMsgList;
    ret = dbAlertLog.getUnPostedList(modelMsgList);
    if (ret && modelMsgList.size() > 0)
    {
        foreach (const auto &msg, modelMsgList)
        {
            if (msg->type == AlertType::type_device_lose)
                emit signalToPostlog_system(3, msg->time);
            else if (msg->type == AlertType::type_shipCollision)
            {
                emit signalToPostlog_alert(3, msg->time, msg->ID);
                if (msg->expiredTime > 0)
                    emit signalToPostlog_alert(4, msg->expiredTime, msg->ID);
            }
            else if (msg->type == AlertType::type_riskarea)
            {
                emit signalToPostlog_alert(1, msg->time, msg->ID);
                if (msg->expiredTime > 0)
                    emit signalToPostlog_alert(2, msg->expiredTime, msg->ID);
            }
        }
    }
    dbAlertLog.updatePosted();
}

bool NetworkTask::postlog_alert(int mtype, qint64 mtime, int minfo)
{
    if (!ENetwork::networkStatus || TOKEN.isEmpty())
        return false;

    emit signalToPostlog_alert(mtype, mtime, minfo);
    return true;
}

bool NetworkTask::postlog_system(int mtype, qint64 mtime)
{
    if (!ENetwork::networkStatus || TOKEN.isEmpty())
        return false;
    emit signalToPostlog_system(mtype, mtime);
    return true;
}

void NetworkTask::postHeartbeat()
{
    if (ENetwork::networkStatus && !TOKEN.isEmpty())
        emit signalToPostHeartbeat();
}

void NetworkTask::setShipType(int shipType)
{
    SIMPLEUPDATE->setShipType(shipType);
}